package com.dashu.core.service;

import com.dashu.base.enums.ReplRyCode;
import com.dashu.base.utils.CopyUtil;
import com.dashu.base.utils.UIDUtil;
import com.dashu.base.utils.VerificationUtil;
import com.dashu.core.dto.gate.*;
import com.dashu.core.handler.VerificationException;
import com.dashu.core.model.GateInTime;
import com.dashu.core.model.GateOutTime;
import com.dashu.core.model.GateRule;
import com.dashu.core.model.QGateRule;
import com.dashu.core.result.PageEnty;
import com.dashu.core.vo.UpdateEntityVO;
import com.dashu.core.vo.gate.*;
import com.google.common.collect.Lists;
import com.querydsl.core.BooleanBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.FlushModeType;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class GateRuleService extends DataService {

    @Autowired
    private CompanyDepartmentService companyDepartmentService;
    @Autowired
    private CompanyPersonalService companyPersonalService;

    @Autowired
    private GateGroupService gateGroupService;
    @Autowired
    private GateDateService gateDateService;
    @Autowired
    private GateInTimeService gateInTimeService;
    @Autowired
    private GateOutTimeService gateOutTimeService;

    @Transactional
    public GateRuleDTO add(GateRuleVO gateRuleVO) {
        GateRule gateRule = CopyUtil.copyEnty(gateRuleVO, GateRule.class);
        try {
            long userId = Long.parseLong(VerificationUtil.getUserId());
            gateRule.setId(UIDUtil.nextId());
            gateRule.setCreateUser(userId);
            gateRule.setCreateTime(System.currentTimeMillis());
            gateRule.setRuleType(gateRuleVO.getRuleType());
            gateRule.setRuleInType(gateRuleVO.getRuleInType());
            gateRuleVO.getGateDate().stream().forEach(ad -> {
                ad.setRuleId(gateRule.getId());
                gateDateService.add(ad);
            });
            gateRuleVO.getGateGroup().stream().forEach(ag -> {
                ag.setRuleId(gateRule.getId());
                ag.setRuleType(gateRuleVO.getRuleType());
                ag.setRuleInType(gateRuleVO.getRuleInType());
                gateGroupService.add(ag);
            });
            entityManager.persist(gateRule);
//            entityManager.flush();
            entityManager.setFlushMode(FlushModeType.AUTO);
        } catch (Exception e) {
            e.printStackTrace();
            throw new VerificationException(ReplRyCode.DATA_NOT_INVALID, ReplRyCode.DATA_NOT_INVALID.getMessage());
        }
        GateRuleDTO gateRuleDTO = CopyUtil.copyEnty(gateRule, GateRuleDTO.class);
        return gateRuleDTO;

    }


    @Transactional
    public GateTimeDTO addTime(GateTimeVO gateTimeVO) {

        GateInTimeVO gateInTimeVo = CopyUtil.copyEnty(gateTimeVO.getGateInTimeVO(), GateInTimeVO.class);
        GateOutTimeVO gateOutTimeVo = CopyUtil.copyEnty(gateTimeVO.getGateOutTimeVO(), GateOutTimeVO.class);
        long id = UIDUtil.nextId();
        long time = System.currentTimeMillis();
        GateTimeDTO gateTimeDTO = new GateTimeDTO();
        gateInTimeVo.setId(id);
        gateInTimeVo.setName(gateTimeVO.getName());
        gateInTimeVo.setCreateTime(time);
        GateInTimeDTO gateInTimeDTO = gateInTimeService.add(gateInTimeVo);
        gateTimeDTO.setGateInTimeDTO(gateInTimeDTO);
        gateOutTimeVo.setId(id);
        gateOutTimeVo.setName(gateTimeVO.getName());
        gateOutTimeVo.setCreateTime(time);
        GateOutTimeDTO gateOutTimeDTO = gateOutTimeService.add(gateOutTimeVo);
        gateTimeDTO.setGateOutTimeDTO(gateOutTimeDTO);
        gateTimeDTO.setId(id);
        return gateTimeDTO;

    }

    @Transactional
    public boolean deleteByGateRuleId(long agateRuleId) throws Exception {
        QGateRule qGateRule = QGateRule.gateRule;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qGateRule.id.eq(agateRuleId));
        GateRule gateRule =
                queryFactory
                        .select(qGateRule)
                        .from(qGateRule)
                        .where(booleanBuilder.getValue())
                        .fetchOne();
        gateDateService.deleteGateData(agateRuleId);
        gateGroupService.deleteGateGroup(agateRuleId, gateRule.getRuleType(), gateRule.getRuleInType());
        entityManager.remove(gateRule);
//            entityManager.flush();
        entityManager.setFlushMode(FlushModeType.AUTO);
        return true;

    }

    @Transactional
    public GateRuleDTO updataByGateRuleId(UpdateEntityVO<GateRuleVO> updateGateRuleVO) throws Exception {
        QGateRule qGateRule = QGateRule.gateRule;
        long userId = Long.parseLong(VerificationUtil.getUserId());
        GateRuleVO gateRuleVO = updateGateRuleVO.getEntityVO();
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qGateRule.id.eq(updateGateRuleVO.getId()));
        GateRule gateRule;
        try {
            gateRule =
                    queryFactory
                            .select(qGateRule)
                            .from(qGateRule)
                            .where(booleanBuilder.getValue())
                            .fetchOne();
//            gateDateService.updataGateData(gateRuleVO.getGateDate(), gateRule.getId());
//            gateGroupService.updataGateGroup(gateRuleVO.getGateGroup(), gateRule.getId(), gateRule.getRuleType(), gateRule.getRuleInType());
            gateRule.setUpdateUser(userId);
            gateRule.setUpdateTime(new Date().getTime());
            gateRule = entityManager.merge(gateRule);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
//        entityManager.flush();
        entityManager.setFlushMode(FlushModeType.AUTO);
        GateRuleDTO GateRuleDTO = CopyUtil.copyEnty(gateRule, GateRuleDTO.class);
        return GateRuleDTO;

    }


    @Transactional
    public GateTimeDTO updataByGateTime(UpdateEntityVO<GateTimeVO> gateTimeEntityVO) throws Exception {
        GateTimeDTO gateTimeDTO = new GateTimeDTO();
        GateTimeVO gateTimeVO = gateTimeEntityVO.getEntityVO();
        GateOutTimeVO gateOutTimeVO = gateTimeVO.getGateOutTimeVO();
        UpdateEntityVO<GateOutTimeVO> gateOutDateVO = new UpdateEntityVO<>();
        gateOutDateVO.setEntityVO(gateOutTimeVO);
        gateOutDateVO.setId(gateTimeEntityVO.getId());
        gateTimeDTO.setGateOutTimeDTO(gateOutTimeService.updataGateData(gateOutDateVO));

        GateInTimeVO gateInTimeVO = gateTimeVO.getGateInTimeVO();
        UpdateEntityVO<GateInTimeVO> gateInDateVO = new UpdateEntityVO<>();
        gateInDateVO.setEntityVO(gateInTimeVO);
        gateInDateVO.setId(gateTimeEntityVO.getId());
        gateTimeDTO.setGateInTimeDTO(gateInTimeService.updataGateData(gateInDateVO));

        return gateTimeDTO;
    }


    @Transactional
    public boolean deleteByGateTime(long timeId) throws Exception {
        gateOutTimeService.deleteGateData(timeId);
        gateInTimeService.deleteGateData(timeId);
        return true;
    }

    @Transactional
    public GateTimeDTO findByGateTime(long timeId) throws Exception {
        GateTimeDTO gateTimeDTO = new GateTimeDTO();
        gateTimeDTO.setGateOutTimeDTO(gateOutTimeService.findGateGroup(timeId));
        gateTimeDTO.setGateInTimeDTO(gateInTimeService.findGateGroup(timeId));
        return gateTimeDTO;
    }

    @Transactional
    public long countTime(PageEnty<GateTimeListVO> timeListVO) throws Exception {
        GateTimeListVO gateTimeListVO = timeListVO.getVo();
        return gateOutTimeService.findByBaseUser(gateTimeListVO.getTimeName()).size();
    }

    @Transactional
    public List<GateTimeDTO> pageGateTimeList(PageEnty<GateTimeListVO> timeListVO) throws Exception {
        List<GateTimeDTO> gateTimeDTOS = Lists.newArrayList();
        GateTimeListVO gateTimeListVO = timeListVO.getVo();
        List<GateOutTimeDTO> gateOutTimeDTOS = gateOutTimeService.findByBaseUser(gateTimeListVO.getTimeName());
        List<GateInTimeDTO> gateInTimeDTOS = gateInTimeService.findByBaseUser(gateTimeListVO.getTimeName());
        for (int i = 0; i < gateOutTimeDTOS.size(); i++) {
            GateTimeDTO gateTimeDTO = new GateTimeDTO();
            gateTimeDTO.setGateOutTimeDTO(gateOutTimeDTOS.get(i));
            gateTimeDTO.setGateInTimeDTO(gateInTimeDTOS.get(i));
            gateTimeDTOS.add(gateTimeDTO);
        }
        return gateTimeDTOS;
    }


    public List<GateRuleDTO> findByCreteUser(PageEnty<Long> baseVo) {
        QGateRule qGateRule = QGateRule.gateRule;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qGateRule.createUser.eq(baseVo.getBaseId()));
        List<GateRule> gateRules = queryFactory
                .select(qGateRule)
                .from(qGateRule)
                .where(booleanBuilder.getValue())
                .fetch();
        List<GateRuleDTO> recycleDTOS = CopyUtil.copyList(gateRules, GateRuleDTO.class);
        return recycleDTOS;

    }

    public GateRuleDTO findByGateRuleId(long gateRuleId) {
        QGateRule qGateRule = QGateRule.gateRule;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qGateRule.id.eq(gateRuleId));
        GateRule gateRule =
                queryFactory
                        .select(qGateRule)
                        .from(qGateRule)
                        .where(booleanBuilder.getValue())
                        .fetchOne();
        List<GateDateDTO> gateDateDTOList = gateDateService.findGateGroup(gateRuleId);
        List<GateGroupDTO> gateGroupDTOList = gateGroupService.findGateGroup(gateRuleId);
        GateRuleDTO gateRuleDTO = CopyUtil.copyEnty(gateRule, GateRuleDTO.class);
        gateRuleDTO.setGateDate(gateDateDTOList);
        gateRuleDTO.setGateGroup(gateGroupDTOList);
        return gateRuleDTO;

    }

    public long ruleListCount(PageEnty<GateRuleListVO> rulePageEntyListVO) {

        long baseId = rulePageEntyListVO.getBaseId() == 0 ? Long.parseLong(VerificationUtil.getUserId()) : rulePageEntyListVO.getBaseId();
        GateRuleListVO gateRuleListVO = rulePageEntyListVO.getVo();
        QGateRule qGateRule = QGateRule.gateRule;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qGateRule.createUser.eq(baseId));
        if (!StringUtils.isEmpty(gateRuleListVO.getRuleName()))
            booleanBuilder.and(qGateRule.createUser.eq(baseId));
        long count = queryFactory
                .select(qGateRule)
                .from(qGateRule)
                .where(booleanBuilder.getValue())
                .fetchCount();
        return count;

    }

    public List<GateRuleListDTO> pageGateRuleList(PageEnty<GateRuleListVO> rulePageEntyListVO) {
        List<GateRuleListDTO> gateRuleListDTOS = Lists.newArrayList();
        long baseId = rulePageEntyListVO.getBaseId() == 0 ? Long.parseLong(VerificationUtil.getUserId()) : rulePageEntyListVO.getBaseId();
        GateRuleListVO gateRuleListVO = rulePageEntyListVO.getVo();
        QGateRule qGateRule = QGateRule.gateRule;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qGateRule.createUser.eq(baseId));
        if (!StringUtils.isEmpty(gateRuleListVO.getRuleName()))
            booleanBuilder.and(qGateRule.ruleName.like("%" + gateRuleListVO.getRuleName() + "%"));
        List<GateRule> gateRules = queryFactory
                .select(qGateRule)
                .from(qGateRule)
                .where(booleanBuilder.getValue())
                .fetch();
        gateRules.stream().forEach(ar -> {
            GateRuleListDTO gateRuleListDTO = CopyUtil.copyEnty(ar, GateRuleListDTO.class);
            List<GateDateDTO> gateDateDTOS = gateDateService.findGateGroup(ar.getId());
            gateRuleListDTO.setGateDate(gateDateDTOS);
            gateRuleListDTOS.add(gateRuleListDTO);
        });

        return gateRuleListDTOS;

    }


}
